home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-13
/
emac16ds.zip
/
BUFFERS.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-08-03
|
20KB
|
832 lines
;History:757,1
;Sat Aug 19 20:49:16 1989 When creating a new buffer, try to avoid compressing memory.
;10-10-88 22:10:05 add inverse_seg to adjust_list.
;06-03-88 23:47:57 improve buffer_check
;05-26-88 23:25:49 added assumes in init_all_buffers
;05-26-88 23:24:13 remove external reference to adjust_buffers
;04-19-88 22:23:33 restore ax after returning from a buffer_free.
;03-29-88 20:59:24 store ' c' or ' e' after expand or compress.
;03-13-88 23:01:42 after doing our work, store ' ' to debug.
;12-11-87 06:52:36 add buffer_check
;12-08-87 22:52:36 add calls to store_debug
;12-06-87 00:32:51 add support for four formSegs.
;12-06-87 00:18:16 let init_forms allocate as many buffers as it wants.
;11-16-87 23:17:35 make memsize private to buffers.asm
;11-10-87 23:02:55 more work to do....
;11-10-87 21:46:38 ensure that we can treat 'data' as if it were a 'bufseg'.
;11-09-87 23:12:03 start writing buffer_free.
.xlist
include emacs.def
include memory.def
bufseg segment public
extrn prev_buffer: word ;= segment of prev buffer (0 if none)
extrn next_buffer: word ;= segment of next buffer (0 if none)
extrn toptop: word
extrn topbot: word
extrn bottop: word
extrn botbot: word
extrn new_size: word
memsize dw ?
extrn bufseg_size: word
bufseg ends
data segment byte public
extrn lomem: byte, lomem_end: byte
public textseg
textseg dw ? ;bufseg of current text buffer.
current_seg dw ? ;bufseg of buffer_free caller.
saveDS dw ?
saveES dw ?
last_para dw ? ;segment after highest buffer
memory_end dw ? ;segment after highest buffer right now.
num_buffers dw ?
amount_needed dw ? ;amount that we need to be free.
free_paras dw ? ;number of free paragraphs left.
insert_number dw ? ;number of buffer being inserted from.
insert_mark db ? ;mark in buffer being inserted from.
extrn w1_windseg: word, w2_windseg: word ;from redisp.asm
extrn inverse_seg: word ;from redisp.asm
extrn syntax_seg: word ;from mintform.asm
extrn formSeg0: word ;from mintform.asm
extrn formSeg1: word ;from mintform.asm
extrn formSeg2: word ;from mintform.asm
extrn formSeg3: word ;from mintform.asm
adjust_list label word
dw textseg ;have to adjust this one.
dw current_seg
dw w1_windseg ;from redisp.asm, window one's buffer.
dw w2_windseg ;from redisp.asm, window two's buffer.
dw inverse_seg
dw syntax_seg
dw formSeg0 ;from mintform.asm
dw formSeg1 ;from mintform.asm
dw formSeg2 ;from mintform.asm
dw formSeg3 ;from mintform.asm
dw saveDS
dw saveES
dw 0
data ends
code segment byte public
;all the routines in this segment are entered with ds=data, es=data
assume cs:code, ds:data, es:data, ss:data
extrn init_forms: near
comment /
buffers:
data
mint string
text
...
a buffer is initially set with bottop=botbot=end of buffer. Then the buffer
is initialized.
/
public init_all_buffers
init_all_buffers:
;enter with bx=> first paragraph of unavailable memory.
;exit with cy if no buffer available.
mov memory_end,bx ;remember where memory ends.
mov last_para,bx ;remember where memory ends.
assume ds:bufseg
mov prev_buffer,0 ;only one buffer so far.
mov next_buffer,0
mov ax,offset lomem
mov topbot,ax
mov bottop,ax
mov botbot,offset lomem_end
assume ds:data
call init_forms ;create as many buffers as init_forms needs.
jc init__all_buffers_1
mov cx,offset bufseg_size
call new_buffer ;create a new buffer.
jc init__all_buffers_1
assume ds:bufseg
call select_buffer ;make this the current buffer.
call init_vars$ ;init most everything
call init_marks ;init the rest.
clc
push es
pop ds
assume ds:data
init__all_buffers_1:
ret
public percent_full
percent_full:
;return the percent full amount in ax.
;destroy ax,cx,dx.
push ds
mov ds,textseg
assume ds:bufseg
mov ax,100
mov cx,memsize
jcxz percent_full_1
mov ax,botbot ;compute the size of the buffer
sub ax,bottop
add ax,topbot
sub ax,toptop
mov dx,0
div cx
cmp dx,0
je percent_full_1
inc ax
percent_full_1:
pop ds
assume ds:data
ret
public buffer_allocate
buffer_allocate:
;entry:
; case cx of
; -1..-32768: report the current buffer number.
; exit: ax=current buffer number.
; 0: create a new buffer.
; exit: ax=new buffer number if enough memory, ax=0 otherwise.
; 1..32767:
; entry: cx=buffer number to select, ax=0 for read/write buffer.
; exit: ax=buffer number if it exists, ax=0 otherwise.
jcxz buffer_allocate_2
or cx,cx ;if cx<0, return buffer number.
js buffer_allocate_4
call find_buffer
jc buffer_allocate_5 ;buffer not found.
push ds
mov ds,dx ;get the current buffer back.
call select_buffer
pop ds
jmp buffer_allocate_4
buffer_allocate_5:
mov ax,0 ;buffer not found.
jmp short buffer_allocate_1
buffer_allocate_2:
;create a new buffer.
mov cx,offset bufseg_size
call new_buffer
mov ax,0 ;failed to create buffer - report it.
jc buffer_allocate_1
assume ds:bufseg
call select_buffer ;make this the current buffer.
call init_vars$ ;init most everything
call init_marks ;init the rest.
push es
pop ds
assume ds:data
buffer_allocate_4:
;return the current buffer number.
mov bx,textseg
call buffer_number ;return number in ax.
buffer_allocate_1:
push es
pop ds
assume ds:data
ret
public buffer_insert
buffer_insert:
;enter with al=mark, cx=buffer number.
;insert the text between point and mark from the given buffer.
;exit with nc if ok, cy if the given buffer doesn't exist, or the specified
; text won't fit.
mov insert_number,cx
mov insert_mark,al
call find_buffer ;find their buffer.
jc buffer_insert_1 ;not found.
;get the size of the inserted text, and make sure we have that much free
;space.
push ds
mov ds,dx
assume ds:bufseg
mov al,insert_mark
call read_mark$ ;we're just interested in the count.
mov ax,textseg ;now free that many bytes.
call buffer_free
pop ds
assume ds:data
jc buffer_insert_1 ;go if it won't fit.
;now find the buffer again, get the mark, and insert it.
mov cx,insert_number
call find_buffer ;this should ALWAYS return nc.
mov al,insert_mark
mov ds,dx
assume ds:bufseg
call read_mark$
mov ax,ds
mov ds,textseg
call insert_string$ ;this should ALWAYS return nc.
jmp short buffer_insert_2
buffer_insert_1:
stc
buffer_insert_2:
push es ;restore ds.
pop ds
assume ds:data
ret
public compact_buffers
compact_buffers:
;exit with bx=first unused paragraph.
call compress
push ds
mov ds,textseg
assume ds:bufseg
; mov cx,1000h ;give the current buffer all that
; call adjust_new_size ; we can.
call expand
call get_last_buffer ;get ds = paragraph of last buffer.
call buffer_paragraphs ;get the size of it.
mov bx,ds
add bx,cx
pop ds
mov last_para,bx
ret
public uncompact_buffers
uncompact_buffers:
mov ax,memory_end
mov last_para,ax
ret
compress:
;move all the buffers as low in memory as they'll go.
;exit with bx=first unused paragraph, num_buffers set to the number of buffers.
mov ax,'*c'
call store_debug
push ds
assume ds:bufseg
mov num_buffers,0
mov ax,ds ;get set to compress data.
mov es,ax
mov di,topbot ;put the bottom at the end of the top.
mov si,bottop ;have to get the copy, just in case.
mov bottop,di ;save the new bottop.
mov cx,botbot
sub cx,si ;same as sub cx,bottop
movmem
mov botbot,di
compress_4:
inc num_buffers
call buffer_paragraphs
mov new_size,cx ;remember it for later.
cmp next_buffer,0 ;was this the last buffer in memory?
je compress_3 ;yes - we're done.
call move_buffer_lower
jmp compress_4
compress_3:
mov bx,ds ;get the para of the last buffer.
call buffer_paragraphs
add bx,cx ;compute the first free segment.
pop ds
assume ds:data
mov ax,last_para ;get the end of memory.
sub ax,bx ;compute the amount free.
mov free_paras,ax ;remember it.
mov ax,' c'
call store_debug
ret
public find_buffer
find_buffer:
;enter with cx=buffer number.
;exit with nc, dx set to that buffer if it exists, cy otherwise.
push ds
assume ds:bufseg
add cx,4 ;allow for the forms buffer(s).
find_buffer_1:
mov dx,next_buffer
cmp dx,0 ;at the end?
je find_buffer_2
mov ds,dx
loop find_buffer_1
mov dx,ds ;get the current buffer back.
pop ds
clc
ret
find_buffer_2:
pop ds
stc
ret
assume ds:data
public new_buffer
new_buffer:
;create a new buffer of size cx.
;exit with cy if there's not enough memory for a new buffer, or else return
; with ds = new buffer.
;first we try it by compressing just the last buffer.
push cx
push cx
call compress_last ;compress just the last buffer.
pop cx
call new_buffer_subr
pop cx
jnc new_buffer_3 ;if it worked, we're okay.
push cx
call compress ;otherwise, compress memory.
pop cx
call new_buffer_subr
new_buffer_3:
ret
compress_last:
;exit with the last buffer in memory compressed.
compress_last_1:
assume ds:bufseg
mov dx,ds ;remember the current buffer.
mov ax,next_buffer ;keep going until we have the
mov ds,ax ; last buffer.
or ax,ax
jne compress_last_1
assume es:bufseg
mov ds,dx ;get the para of the last buffer.
mov es,dx
mov di,topbot
mov si,es:bottop ;have to get the copy, just in case.
mov es:bottop,di ;save the new bottop.
mov cx,es:botbot
sub cx,si ;same as sub cx,bottop
movmem
mov es:botbot,di
mov ax,data
mov es,ax
mov ds,ax
assume ds:data, es:data
ret
new_buffer_subr:
;see if there's enough memory for the new buffer, and create it if there is.
push cx
new_buffer_2:
assume ds:bufseg
mov dx,ds ;remember the current buffer.
mov ax,next_buffer ;keep going until we have the
mov ds,ax ; last buffer.
or ax,ax
jne new_buffer_2
mov ds,dx ;get the para of the last buffer.
call buffer_paragraphs ;compute the size of it.
add dx,cx ;find the end of it.
pop cx
mov ax,cx
add ax,0fh ;get the size rounded up.
shr ax,1
shr ax,1
shr ax,1
shr ax,1
add ax,dx
cmp ax,last_para ;is there enough memory for new buffer?
jae new_buffer_1 ;no.
mov next_buffer,dx ;link to the new buffer.
mov ax,ds
mov ds,dx
mov prev_buffer,ax ;link back to the old buffer.
mov next_buffer,0 ;and no link to a new buffer.
mov topbot,cx ;start with an empty buffer.
mov bottop,cx
mov botbot,cx
clc
ret
new_buffer_1:
push es
pop ds
assume ds:data
stc
ret
code ends
code segment byte public
;all the code in this segment is entered with ds=bufseg, es=data
assume cs:code, ds:bufseg, es:data
;the following externs are in 'memory'
extrn init_vars$: near
extrn insert_string$: near
extrn read_mark$: near
;the following externs are in 'marks'
extrn init_marks: near
;the following externs are in machine dependent.
extrn store_debug: near
public buffer_free, expand, adjust_all, adjust_new_size
public adjust_segments, select_buffer, move_buffer_higher
public move_buffer_lower, buffer_paragraphs
public buffer_check
buffer_check:
;exit with zr if all is ok, nz if we have a bad link.
push ds
mov ax,ss
mov ds,ax
mov cx,256
buffer_check_1:
cmp next_buffer,0 ;if we're done, exit.
je buffer_check_2
mov ax,ds ;remember this buffer.
if 0
mov bx,botbot
add bx,10h ;round up to next paragraph.
rcr bx,1 ;ensure that 65536 bytes becomes
shr bx,1 ; 1000h paragraphs.
shr bx,1
shr bx,1
add bx,ax ;compute the next possible location
cmp bx,next_buffer ; for the next buffer.
ja buffer_check_2 ;go if we somehow overlap.
endif
mov ds,next_buffer ;go to the next buffer.
cmp ax,prev_buffer ;does the next buffer point to us?
loope buffer_check_1 ;keep going if we're still ok.
buffer_check_2:
pop ds
ret
public buffer_number
buffer_number:
;enter with bx=paragraph of buffer.
;exit with ax=number of buffer.
push ds
mov ax,ss
mov ds,ax
xor ax,ax
buffer_number_1:
mov dx,ds
cmp dx,bx ;is this the one we're looking for.
je buffer_number_2 ;yes - we've got its number.
mov ds,next_buffer ;get the next buffer
inc ax
jmp buffer_number_1
buffer_number_2:
pop ds
sub ax,4 ;allow for the forms buffer(s).
ret
buffer_free:
;ensure that the buffer in ax has cx bytes free. If it doesn't, reallocate
; memory between the buffers. Return with cy if we cannot get enough memory.
; return with nc, ax = new location of buffer.
mov saveDS,ds
mov ds,ax
assume ds:bufseg, es:nothing
mov ax,bottop ;get the free space size.
sub ax,topbot
cmp cx,ax ;go if we have that much space.
ja buffer_free_1
mov ax,ds
mov ds,saveDS
clc
ret
buffer_free_1:
push bx
push cx
push dx
push si
push di
mov saveES,es
mov amount_needed,cx ;remember how much we need.
mov current_seg,ds
mov ax,ss
mov ds,ax
call compress ;move them down all the way.
mov ds,current_seg
;compact buffers also sets new_size to the new total size of the buffer,
; and sets num_buffers to the number of buffers, and sets free_paras to
; the number of free paragraphs.
mov cx,amount_needed ;compute the amount for this buffer.
add cx,0fh
rcr cx,1 ;ensure that 65536 bytes becomes
shr cx,1 ; 1000h paragraphs.
shr cx,1
shr cx,1
cmp cx,ax ;do we have that much?
ja buffer_free_2 ; no - it's hopeless.
mov ax,new_size ;get the current size of the buffer.
add ax,cx ; add in the size that we need.
cmp ax,1000h ;more than a buffer can possibly hold?
jae buffer_free_2 ; yes - it's hopeless
;now give our buffer the amount that it needs.
call adjust_new_size ;if we don't have enough memory,
mov ax,free_paras ;get the free paragraphs, and divide it
mov dx,0 ; evenly among all the buffers.
div num_buffers
mov cx,ax ;allocate the memory evenly.
call adjust_all ;adjust all the buffers.
cmp free_paras,0 ;is there any memory left?
je buffer_free_3 ;no - we're done allocating.
mov cx,65535 ;now allocate the rest of the memory.
call adjust_all
buffer_free_3:
call expand
clc
jmp short buffer_free_4
buffer_free_2:
stc
buffer_free_4:
mov es,saveES
pop di
pop si
pop dx
pop cx
pop bx
mov ax,ds
mov ds,saveDS
ret
assume es:data
expand:
;exit with ds=data.
mov ax,'*e'
call store_debug
call get_last_buffer
;now we have ds=paragraph of the last buffer, dx->new location for this buffer.
expand_2:
mov ax,dx ;get the destination paragraph.
call move_buffer_higher ;move the buffer up.
mov ax,prev_buffer ;get the previous buffer.
or ax,ax
je expand_1 ;go if we're done.
mov dx,ds ;remember where we are now.
mov ds,ax
sub dx,new_size ;find out where we'll be next.
jmp expand_2
expand_1:
mov ax,' e'
call store_debug
ret
get_last_buffer:
;exit with dx = paragraph of new last buffer,
; ds = paragraph of current last buffer.
mov dx,ss ;add up the new sizes of the buffers.
mov ds,dx
get_last_buffer_1:
cmp next_buffer,0 ;is this the last buffer?
je get_last_buffer_2 ;yes - we're done.
add dx,new_size ;no - add in the size of this buffer,
mov ds,next_buffer ;and go to the next buffer.
jmp get_last_buffer_1
get_last_buffer_2:
ret
adjust_all:
;enter with cx = amount of memory to allocate to each buffer.
;add this amount to the new size of each buffer.
push ds
mov ax,ss ;get the first buffer.
mov ds,ax
adjust_all_1:
call adjust_new_size
mov ax,next_buffer ;is this the last buffer?
cmp ax,0
mov ds,ax
jne adjust_all_1 ;no - go do another.
pop ds
ret
adjust_new_size:
;enter with ds = segment whose new_size we're adjusting.
; free_paras = the number of free paragraphs to allocate,
; cx = number of paragraphs to allocate to the buffer in ds.
;return with cy if we don't have enough memory to allocate that many.
mov ax,1000h ;get the max buffer size.
sub ax,new_size ;subtract off the new size.
cmp ax,cx ;more than we want?
jb adjust_new_size_1 ; no - we can only give it this much.
mov ax,cx ; yes - only give it as much as we want.
adjust_new_size_1:
cmp ax,free_paras ;more than we have?
jb adjust_new_size_2 ; no - we can give it this much.
mov ax,free_paras ; yes - only give it as much as we have.
adjust_new_size_2:
add new_size,ax
sub free_paras,ax ;say that we have that many fewer.
ret
adjust_segments:
;enter with bx = current bufseg, ax = new location of that bufseg.
push si
push di
mov si,offset adjust_list
adjust_segments_1:
mov di,data:[si] ;get the next pointer.
add si,2
or di,di ;exit on null.
je adjust_segments_2
cmp data:[di],bx ;is this the old one?
jne adjust_segments_1 ;no.
mov data:[di],ax ;yes - update with the new.
jmp adjust_segments_1
adjust_segments_2:
pop di
pop si
ret
select_buffer:
;enter with ds=buffer to select.
mov textseg,ds ;save the new current buffer.
mov ax,botbot
sub ax,toptop
mov dx,0
mov cx,100
div cx
mov memsize,ax
ret
move_buffer_higher:
;move a buffer higher in memory.
;enter with ax = new buffer location, new_size = new buffer size (in paras).
push es
mov bx,ds
call adjust_segments
mov es,ax
assume es:bufseg
std ;moving from low to high, go backwards.
mov si,botbot ;get the last location used in a buffer,
dec si
mov di,new_size ;compute the new last location in the
shl di,1 ; buffer.
shl di,1
shl di,1
shl di,1
dec di
dec di
mov cx,botbot ;compute the amount to move.
sub cx,bottop
mov botbot,di
inc botbot
rep movsb
mov bottop,di
inc bottop
mov si,topbot ;now move the bottom part of the buffer.
dec si
mov di,si
mov cx,topbot
rep movsb
cld ;now update the previous and next ptrs.
mov si,es:prev_buffer
mov di,es:next_buffer
or si,si ;is there a previous buffer?
je move_buffer_higher_1 ;no.
mov ds,si
mov next_buffer,ax ;tell it where we are now.
move_buffer_higher_1:
or di,di ;is there a next buffer?
je move_buffer_higher_2 ;no.
mov ds,di ;get the next buffer.
mov prev_buffer,ax ;tell it where we are now.
move_buffer_higher_2:
mov ds,ax ;and return ds = us.
pop es
assume es:data
ret
move_buffer_lower:
;move a buffer lower in memory.
;enter with ds=buffer before the one to be lowered.
;exit with ds=new location of lowered buffer.
call buffer_paragraphs
mov ax,ds ;get the base of this buffer.
add ax,cx ;get the end of this buffer.
mov bx,next_buffer
mov next_buffer,ax ;save the pointer to the next buffer.
mov cx,ds
mov ds,bx ;get paragraph of buffer to move.
mov prev_buffer,cx ;now remember where the previous buffer is.
call adjust_segments
push es
mov es,ax ;move the bottom down to the new buffer.
assume es:bufseg
mov si,0
mov di,si
mov cx,topbot
movmem
mov si,es:bottop ;have to get the copy, just in case.
mov es:bottop,di ;save the new bottop.
mov cx,es:botbot
sub cx,si ;same as sub cx,bottop
movmem
mov es:botbot,di
pop es
assume es:data
mov ds,ax ;get new para of just moved buffer.
ret
buffer_paragraphs:
;compute the number of paragraphs used by a buffer.
;enter with ds=buffer
;exit with cx=number of paragraphs.
mov cx,botbot
add cx,10h ;round up to next paragraph.
rcr cx,1 ;ensure that 65536 bytes becomes
shr cx,1 ; 1000h paragraphs.
shr cx,1
shr cx,1
ret
code ends
end